import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;

import EventPackage.Event;
import EventPackage.EventManagerInterface;
import EventPackage.EventQueue;


public class SecurityMonitorB extends Thread implements ActionListener{
	// these items are used simply for User Interaction purposes
	private JFrame thisFrame;
	private JTextArea notificationArea; // textually represents the state of the alarm
	private JButton armButton;
	private JButton disarmButton;
	private JButton doorConfirmButton;
	private JButton windowConfirmButton;
	private JButton motionConfirmButton;
	private JButton indicator; // turns Red if any alarm goes off
	private JLabel systemState; // indicates
	private JButton fireButton;
	private JButton stopSprinkler;
	private JButton startSprinkler;
	private int sprinklerTimeout = 15;
	
	private EventManagerInterface em = null;// Interface object to the event manager
	private boolean Registered;		// Signifies that this class is registered with an event manager.
	private String EvtMgrIP = null;			// Event Manager IP address
	private String EvtMgrName = null;
	
	private boolean windowBroken = false;
	private boolean doorBroken = false;
	private boolean motionDetected = false;
	private boolean fireDetected = false;
	private boolean sprinklerOn = false;
	
	public static void main(String args[]){
		SecurityMonitorB monitor = null;
		
 		if ( args.length > 0 )
 		{
 			if(args.length > 1)
 			{
				// event manager is not on the local system
	 			monitor = new SecurityMonitorB( args[0], args[1] );
 			}
 			else
 			{
 				// event manager is not on the local system
	 			monitor = new SecurityMonitorB( args[0] );
 			}

		} else {
			monitor = new SecurityMonitorB();

		} // if
 		
 		if (monitor.IsRegistered() ){
			monitor.start(); // Here we start the monitoring and control thread
		}
 		else{
 			System.out.println("Unable to start the Security Monitor...");
 		}
 		
 		try
 		{
	 		if(args.length > 3){
		 		//Use the following code for invoking the hb sender ..assuming args 2 and 3 exist. Add checks for that
		 		EventManagerInterface hbManager = new EventManagerInterface(args[2] , args[3]);
		 		EventPackage.Event evt = new Event((int) 12);
		 		evt.SetSenderId(monitor.getEM().GetMyId());
		 		HeartBeat.startThread(hbManager, evt, 5000);
		 		
		 		if(args.length == 6)
		 		{
			 		//Use the following code for invoking the hb sender ..assuming args 2 and 3 exist. Add checks for that
		 			String name = args[4];
		 			String description = args[5];
			 		EventPackage.Event evt2 = new Event((int) 11, name+'%'+description);
			 		evt2.SetSenderId(monitor.getEM().GetMyId());
			 		HeartBeat.startThread(hbManager, evt2, 30000);
		 		}
	 		}
 		}
 		catch(Exception e)
 		{
 			System.out.println("Unable to link with the Heartbeat monitor Event Manager");
 			JOptionPane.showMessageDialog(null, "Unable to link with the Heartbeat monitor Event Manager");
 		}

	}
	
	public SecurityMonitorB(){
		// event manager is on the local system
		try
		{
			// Here we create an event manager interface object. This assumes
			// that the event manager is on the local machine
			em = new EventManagerInterface();
			Registered = true;
			initialize();
		}

		catch (Exception e)
		{
			System.out.println("SecurityMonitorB::Error instantiating event manager interface: " + e);
			JOptionPane.showMessageDialog(null, "SecurityMonitorB::Error instantiating event manager interface: " + e);
			Registered = false;

		} // catch
	}
	
	public SecurityMonitorB( String EvmIpAddress )
	{
		// event manager is not on the local system
		EvtMgrIP = EvmIpAddress;

		try
		{
			// Here we create an event manager interface object. This assumes
			// that the event manager is NOT on the local machine
			em = new EventManagerInterface( EvtMgrIP );
			Registered = true;
			initialize();
		}

		catch (Exception e)
		{
			System.out.println("SecurityMonitorB::Error instantiating event manager interface: " + e);
			JOptionPane.showMessageDialog(null, "SecurityMonitorB::Error instantiating event manager interface: " + e);
			Registered = false;

		} // catch

	} // Constructor
	
	public SecurityMonitorB( String EvmIpAddress, String EvmName )
	{
		// event manager is not on the local system
		EvtMgrIP = EvmIpAddress;
		EvtMgrName = EvmName;

		try
		{
			// Here we create an event manager interface object. This assumes
			// that the event manager is NOT on the local machine
			em = new EventManagerInterface( EvtMgrIP, EvtMgrName );
			Registered = true;
			initialize();
		}

		catch (Exception e)
		{
			System.out.println("SecurityMonitorB::Error instantiating event manager interface: " + e);
			JOptionPane.showMessageDialog(null, "SecurityMonitorB::Error instantiating event manager interface: " + e);
			Registered = false;

		} // catch

	} // Constructor
	
	private void initialize(){
		thisFrame = new JFrame("SECURITY MONITOR");
		thisFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		thisFrame.setLayout(new BorderLayout());
		
		indicator = new JButton();
		indicator.setBackground(Color.YELLOW);
		indicator.setEnabled(false);
		
		systemState = new JLabel("System Disarmed");
		
		notificationArea = new JTextArea();
		notificationArea.setEditable(false);
		
		JPanel northPanel = new JPanel(new BorderLayout());
		northPanel.add(indicator, BorderLayout.NORTH);
		northPanel.add(notificationArea, BorderLayout.CENTER);
		northPanel.add(systemState, BorderLayout.SOUTH);
		
		thisFrame.add(northPanel, BorderLayout.NORTH);
		
		JPanel centerPanel = new JPanel(new GridLayout(3,5));
		
		armButton = new JButton("ARM SYSTEM");
		armButton.addActionListener(this);
		
		disarmButton = new JButton("DISARM SYSTEM");
		disarmButton.addActionListener(this);
		
		centerPanel.add(new JLabel());
		centerPanel.add(armButton);
		centerPanel.add(new JLabel());
		centerPanel.add(disarmButton);
		centerPanel.add(new JLabel());

		fireButton = new JButton("NO FIRE");
		fireButton.setBackground(Color.GRAY);
		fireButton.setEnabled(false);
		fireButton.addActionListener(this);
		
		
		stopSprinkler = new JButton("SPRINKLER OFF");
		stopSprinkler.setBackground(Color.GRAY);
		stopSprinkler.setEnabled(false);
		stopSprinkler.addActionListener(this);
		
		startSprinkler = new JButton("START SPRINKLER");
		startSprinkler.setBackground(Color.YELLOW);
		startSprinkler.addActionListener(this);
		
		centerPanel.add(new JLabel());
		centerPanel.add(stopSprinkler);
		centerPanel.add(fireButton);
		centerPanel.add(startSprinkler);
		centerPanel.add(new JLabel());
		
		windowConfirmButton = new JButton("WINDOW OK");
		windowConfirmButton.addActionListener(this);
		windowConfirmButton.setBackground(Color.WHITE);
		windowConfirmButton.setEnabled(false);
		
		doorConfirmButton = new JButton("DOOR OK");
		doorConfirmButton.addActionListener(this);
		doorConfirmButton.setBackground(Color.WHITE);
		doorConfirmButton.setEnabled(false);
		
		motionConfirmButton = new JButton("MOTION OK");
		motionConfirmButton.addActionListener(this);
		motionConfirmButton.setBackground(Color.WHITE);
		motionConfirmButton.setEnabled(false);
		
		centerPanel.add(windowConfirmButton);
		centerPanel.add(new JLabel());
		centerPanel.add(doorConfirmButton);
		centerPanel.add(new JLabel());
		centerPanel.add(motionConfirmButton);
		
		thisFrame.add(centerPanel, BorderLayout.CENTER);
		thisFrame.setSize(900, 200);
		thisFrame.setVisible(true);
	}
	
	public boolean IsRegistered()
	{
		return(Registered);
	}

	public void run(){
		Event Evt = null;				// Event object
		EventQueue eq = null;			// Message Queue
		int	Delay = 1000;				// The loop delay (1 second)
		boolean Done = false;			// Loop termination flag

		if (em != null)
		{
			while ( !Done )
			{
				// Here we get our event queue from the event manager
				try
				{
					eq = em.GetEventQueue();
				} // try
	
				catch( Exception e )
				{
					JOptionPane.showMessageDialog(null,"Error getting event queue::" + e );
				} // catch
	
				int qlen = eq.GetSize();
	
				for (int i=0; i<qlen; i++)
				{
					Evt = eq.GetEvent();
					
					switch(Evt.GetEventId())
					{
						case 6:
							if(systemState.getText().equals("System Armed"))
							{
								if(Evt.GetMessage().equals("WB")){
									windowBroken = true;
								}// if
								else if(Evt.GetMessage().equals("DB")){
									doorBroken = true;
								}// else if
								else if(Evt.GetMessage().equals("MD")){
									motionDetected = true;
								}// else if
								else{
									System.out.println("Unknown Event Detected - ID6:" + Evt.GetMessage());
								}
							}
							break;
							
						case 8:
							if(systemState.getText().equals("System Armed")){
								fireDetected = true;
							}
							break;
							
						case 13:
							if(Evt.GetMessage().equals("AM")){
								systemState.setText("System Armed");
							}// if
							else if(Evt.GetMessage().equals("DA")){
								systemState.setText("System Disarmed");
								indicator.setBackground(Color.YELLOW);
							}// else if
							else{
								System.out.println("Unknown Event Detected - ID13:" + Evt.GetMessage());
							}
							break;
							
						case 14:
							if(Evt.GetMessage().equals("SO")){
								turnOffSprinkler();
							}// if
							else if(Evt.GetMessage().equals("SA")){
								turnOnSprinkler();
							}// else if
							else{
								System.out.println("Unknown Event Detected - ID13:" + Evt.GetMessage());
							}
							break;
							
						case 15:
							fireButton.setBackground(Color.GRAY);
							fireButton.setText("NO FIRE");
							fireButton.setEnabled(false);
							fireDetected = false;
							break;
						
						// case 99 exits the system
						case 99:
							Done = true;
							break;
					}// switch
				}// for
				
				if(systemState.getText().equals("System Armed"))
				{
					// consoleLine will print the console output
					StringBuffer consoleLine = new StringBuffer();
					if(windowBroken){
						consoleLine.append("Window Broken \n");
						windowConfirmButton.setBackground(Color.YELLOW);
						windowConfirmButton.setText("WINDOW BROKEN");
						windowConfirmButton.setEnabled(true);
					}
					if(doorBroken){
						consoleLine.append("Door Broken \n");
						doorConfirmButton.setBackground(Color.YELLOW);
						doorConfirmButton.setText("DOOR BROKEN");
						doorConfirmButton.setEnabled(true);
					}
					if(motionDetected){
						consoleLine.append("Motion Detected \n");
						motionConfirmButton.setBackground(Color.YELLOW);
						motionConfirmButton.setText("MOTION DETECTED");
						motionConfirmButton.setEnabled(true);
					}
					if(fireDetected){
						consoleLine.append("Fire Detected \n");
						fireButton.setBackground(Color.YELLOW);
						fireButton.setText("STOP FIRE ALARM");
						fireButton.setEnabled(true);
						
						if(!sprinklerOn)
						{
							// sprinklerControl section
							if(sprinklerTimeout > 0)
							{
								sprinklerTimeout--;
								startSprinkler.setText("START SPRINKLER" + " -- " + sprinklerTimeout);
								
								stopSprinkler.setEnabled(true);
								stopSprinkler.setBackground(Color.YELLOW);
								stopSprinkler.setText("CANCEL SPRINKLER");
							}
							else if (sprinklerTimeout == 0)
							{
								requestTurnOnSprinkler();
							}
							else
							{
								startSprinkler.setText("START SPRINKLER");
							}
						}
						else
						{
							// do nothing, we just wait for the user to press the buttons
						}
					}
					
					// if nothing was detected
					if(!windowBroken && !doorBroken && !motionDetected && !fireDetected){
						indicator.setBackground(Color.GREEN);
						sprinklerTimeout = 15;
					}
					else{
						indicator.setBackground(Color.RED);
					}
					
					// set the text
					notificationArea.setEditable(true);
					notificationArea.setText(new String(consoleLine));
					notificationArea.setEditable(false);
				}
				
				try
				{
					Thread.sleep( Delay );
				} // try	
				catch( Exception e )
				{
					System.out.println( "Sleep error:: " + e );
					JOptionPane.showMessageDialog(null, "SLEEP ERROR");
				} // catch
			} // while
		} 
		else {
			System.out.println("Unable to register with the event manager.\n\n" );
	
		} // if
		
	}
	
	private void turnOnSprinkler()
	{
		sprinklerOn = true;
		sprinklerTimeout = 0;
		
		startSprinkler.setText("SPRINKLER ON");
		startSprinkler.setEnabled(false);
		startSprinkler.setBackground(Color.GRAY);
		
		stopSprinkler.setEnabled(true);
		stopSprinkler.setBackground(Color.YELLOW);
		stopSprinkler.setText("STOP SPRINKLER");
	}
	
	private void requestTurnOnSprinkler()
	{
		Event evt = new Event(10, "SA");
		try {
			em.SendEvent(evt);
		}
		catch (Exception e) {
			JOptionPane.showMessageDialog(null, "Error sending Stop Fire Alarm event.");
		}
	}
	
	private void turnOffSprinkler()
	{
		sprinklerOn = false;
		sprinklerTimeout = 15;
		
		startSprinkler.setText("TURN SPRINKLER ON");
		startSprinkler.setBackground(Color.YELLOW);
		startSprinkler.setEnabled(true);
		
		stopSprinkler.setEnabled(false);
		stopSprinkler.setBackground(Color.GRAY);
		stopSprinkler.setText("SPRINKLER OFF");
	}
	
	private void requestTurnOffSprinkler()
	{
		Event evt = new Event(10, "SO");
		try {
			em.SendEvent(evt);
		}
		catch (Exception e) {
			JOptionPane.showMessageDialog(null, "Error sending Stop Fire Alarm event.");
		}
	}

	public void actionPerformed(ActionEvent arg0) {
		JButton button = (JButton)arg0.getSource();
		
		if(button == armButton){
			arm();
		}
		else if (button == disarmButton){
			disarm();
		}
		else if (button == motionConfirmButton){
			motionConfirmButton.setBackground(Color.WHITE);
			motionConfirmButton.setText("MOTION OK");
			motionConfirmButton.setEnabled(false);
			motionDetected = false;
		}
		else if (button == doorConfirmButton){
			doorConfirmButton.setBackground(Color.WHITE);
			doorConfirmButton.setText("DOOR OK");
			doorConfirmButton.setEnabled(false);
			doorBroken = false;
		}
		else if (button == windowConfirmButton){
			windowConfirmButton.setBackground(Color.WHITE);
			windowConfirmButton.setText("WINDOW OK");
			windowConfirmButton.setEnabled(false);
			windowBroken = false;
		}
		else if (button == fireButton){
			Event evt = new Event(9, "");
			try {
				em.SendEvent(evt);
			}
			catch (Exception e) {
				JOptionPane.showMessageDialog(null, "Error sending Stop Fire Alarm event.");
			}
		}
		else if (button == stopSprinkler)
		{
			if(stopSprinkler.getText().equals("CANCEL SPRINKLER"))
			{
				sprinklerTimeout = -1;
				stopSprinkler.setText("SPRINKLER OFF");
				stopSprinkler.setEnabled(false);
				stopSprinkler.setBackground(Color.GRAY);
			}
			else
			{
				requestTurnOffSprinkler();
			}
		}
		else if (button == startSprinkler)
		{
			requestTurnOnSprinkler();
		}
	}

	private void disarm() {
		Event evt = new Event(7, "DA");
		try {
			em.SendEvent(evt);
		} 
		catch (Exception e) {
			JOptionPane.showMessageDialog(null, "Error sending Disarm event.");
		}
	}

	private void arm() {
		Event evt = new Event(7, "AM");
		try {
			em.SendEvent(evt);
		} 
		catch (Exception e) {
			JOptionPane.showMessageDialog(null, "Error sending Arm event.");
		}
	}
	
	public EventManagerInterface getEM(){
		return em;
	}
	
}
